package jvm.VMExecSubsystem;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @author msi
 */
public class DynamicProxyTest {

    interface IHello {
        void sayHello();
    }

    static class Hello implements IHello {
        @Override
        public void sayHello() {
            System.out.println("hello world");
        }
    }

    static class DynamicProxy implements InvocationHandler {

        Object originalObj;

        Object bind(Object originalObj) {
            this.originalObj = originalObj;
            return Proxy.newProxyInstance(originalObj.getClass().getClassLoader(), originalObj.getClass().getInterfaces(), this);
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("welcome");
            return method.invoke(originalObj, args);
        }
    }

    public static void main(String[] args) {
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true"); //这段代码可以将动态代理生成的class文件保存在本地 会在根目录下生成。
        IHello hello = (IHello) new DynamicProxy().bind(new Hello());
        hello.sayHello();
    }
}

/**
 * 在代码中的黑匣子就是 Proxy.newProxyInstance方法，它会生成一个增强过的IHello对象。
 * 将该java文件的class文件反编译之后复制到 $Proxy0。这个代理类的实现代码也很简单，它为传入接口中的每一个方法，以及从Object继承类的方法都生成了对应的实现，并且统一调用了InvocationHandler对象的invoke方法。代码中的this.h
 * 就是Proxy中保存的InvocationHandler的实例变量。各个方法的区别只有传入的参数和Method对象有所不同而已，所以无论调用动态代理的那个方法，实际上都是在执行InvocationHandler::invoke()中的代理逻辑。
 * 这个例子中并没有讲到generateProxyClass()方法具体是如何产生代理类 $Proxy0 的字节码的。大致的生成过程其实就是根据class文件的格式规范去拼装字节码，其中ProxyGenerator的源码就是在拼装字节码。
 */
